//
// Created by shen on 2025/2/20.
//


#include "FFSeperator.h"


FFSeperator::FFSeperator(const char *url,FFStatus *ffStatus,JavaCallHelper *_javaCallHelper):javaCallHelper(_javaCallHelper){
   strcpy(this->path,url);
   this->ffStatus=ffStatus;
//    this->queue = new SafeQueue(kzgPlayerStatus);
}


void FFSeperator::onDecodeReady() {

    if (mAudioPalyer == nullptr){
        LOGCATE("mAudioPalyer is null");
    }
    if (mVideoParam == nullptr){
        return;
    }
    mVideoParam->audioPlayer=mAudioPalyer;
    //关闭非关键帧的环路滤波，seek 大GOP要快100ms左右

    int ret=0;
    int count = 0;
    int countAdio = 0;
    mVideoParam->play();
    mAudioPalyer->play();


    while(ffStatus!= nullptr&& !ffStatus->exit){
        if (!ffStatus->isFramePreview){
            //正常播放只缓存40帧解码前的音频
            if (mAudioPalyer->queue->getQueueSize() > 40){
                av_usleep(1000*100);
                continue;
            }
        }


        //超过了缓存
        if (mVideoParam->queue->getQueueSize() > 40){
            av_usleep(1000*20);
            continue;
        }

        AVPacket *avPacket=av_packet_alloc();
        ret = av_read_frame(formatContext,avPacket);
        if (ret==0) {

            if (mAudioPalyer != nullptr && avPacket->stream_index == mAudioPalyer->streamIndex) {
                LOGCATE("count audio = %s", avPacket->data);
                mAudioPalyer->queue->putAvPacket(avPacket);
            } else if (avPacket->stream_index == mVideoParam->streamIndex) {
                count++;
                LOGCATE("count = %d", count);
//            if ((*mVideoParam->avCodecConext)->skip_frame != AVDISCARD_DEFAULT && (
//                avPacket->pts *av_q2d( mVideoParam->time_base)* AV_TIME_BASE) > (mVideoParam->seekTime - 1000000)){
//                (*mVideoParam->avCodecConext)->skip_frame = AVDISCARD_DEFAULT;
//            } else if (*mVideoParam->ffstatus->isBackSeekFramePreview ){
//                (*mVideoParam->avCodecConext)->skip_frame = AVDISCARD_NONREF;
//            }

                mVideoParam->queue->putAvPacket(avPacket);
                tempIndex++;
            }
        }else{
            av_packet_free(&avPacket);
            av_free(avPacket);
            while (ffStatus!= nullptr&&!ffStatus->exit){
                if (mVideoParam->queue->getQueueSize()>0) {
                    av_usleep(1000 * 20);
                    //LOGE("55555555555");
                    continue;
                }else{
                    break;
                }

            }
            continue;
        }
    }

    if (javaCallHelper != NULL){
        javaCallHelper->onStatus(THREAD_CHILD,2);
    }
    SLog::GetInstance()->getLogger()->info("success");


}
int avformate_callback(void *ctx){
    FFSeperator *ffseperator=(FFSeperator*)ctx;
    SLog::GetInstance()->getLogger()->debug("avformate_callback");
    return 0;


}




void FFSeperator::onPrepare(FFSeperator *mFFSeperator)
{
    mFFSeperator->initSeparator(); // 初始化
    mFFSeperator->getAvcoeecContext(mFFSeperator->mAudioPalyer->avCodecParameters,&(mFFSeperator->mAudioPalyer->avCodecConext));
    mFFSeperator->getAvcoeecContext(mFFSeperator->mVideoParam->avCodecParameters,&(mFFSeperator->mVideoParam->avCodecConext));
    mFFSeperator->getJavaCallHelper()->onStatus(THREAD_CHILD,1);
    mFFSeperator->getJavaCallHelper()->onChangeSize(THREAD_CHILD,mFFSeperator->mVideoParam->avCodecConext->width,mFFSeperator->mVideoParam->avCodecConext->height);
    LOGCATI("fps = %d duration = %d width = %d height = %d",mFFSeperator->mVideoParam->fps,mFFSeperator->mVideoParam->duration,
            mFFSeperator->mVideoParam->avCodecConext->width,mFFSeperator->mVideoParam->avCodecConext->height);
}







int FFSeperator::getAvcoeecContext(AVCodecParameters *avCodecParamters,
                                    AVCodecContext **avCodecContext) {
    std::lock_guard<std::mutex> lock(init_mutex);
    int ret;
    //查找解码器对象
    const AVCodec *avCodec=avcodec_find_decoder(avCodecParamters->codec_id);

    if (avCodec== nullptr){
        SLog::GetInstance()->getLogger()->info("can't find avcodec ");
        return -1;
    }
    LOGCATI("url = %s",path);
    //解码器上下文
    *avCodecContext= avcodec_alloc_context3(avCodec);

    if (!*avCodecContext){
        return -1;
    }


    ret = avcodec_parameters_to_context(*avCodecContext,avCodecParamters);
    if (ret<0){
        SLog::GetInstance()->getLogger()->info("can't avcodec parameters to context");
        return -1;
    }

    (*avCodecContext)->thread_type=FF_THREAD_FRAME;
    (*avCodecContext)->thread_count=2;

    //打开解码器
    ret= avcodec_open2(*avCodecContext,avCodec,0);
    if (ret!=0){
        return -1;
    }
    (*avCodecContext)->skip_loop_filter= AVDISCARD_NONKEY;


    const AVBitStreamFilter* pfilter=av_bsf_get_by_name("h264_mp4toannexb");
    av_bsf_alloc(pfilter,&bsf_ctx);


    return 0;
}
void FFSeperator::onStart(FFSeperator *mFFSeperator) {

    mFFSeperator->onDecodeReady();

}
void FFSeperator::initSeparator() {
    std::lock_guard<std::mutex> lock(init_mutex);
//    SLog::GetInstance()->getLogger()->debug("open file fail");
//    av_register_all();
    avformat_network_init();
    formatContext=avformat_alloc_context();
    //when rtmp is terminal ，drop
    formatContext->interrupt_callback.callback=avformate_callback;
    formatContext->interrupt_callback.opaque=this;
//    formatContext->probesize=11;

    int ret=avformat_open_input(&formatContext,path, nullptr, nullptr);
    LOGCATI("avformat_open_input = %s",path);
    if (ret<0){
//        LOGCATI("");
        FFERRORMESSAGE("open file failed");
//        SLog::GetInstance()->getLogger()->debug();
        avformat_close_input(&formatContext);
        avformat_free_context(formatContext);
        formatContext= nullptr;
        return;
    }

    ret=avformat_find_stream_info(formatContext, NULL);
    if (ret<0){
        avformat_close_input(&formatContext);
        avformat_free_context(formatContext);
        formatContext= nullptr;
        return;
    }


    for (int i = 0; i < formatContext->nb_streams; ++i){
        if (formatContext->streams[i]->codecpar->codec_type==AVMEDIA_TYPE_VIDEO){
//            videoIndex=i;
            mVideoParam=new VideoPlayer(ffStatus);
            //set render
            mVideoParam->setGLRender(VideoGLRender::GetInstance());
            mVideoParam->streamIndex=i;
            mVideoParam->timeBase=formatContext->streams[i]->time_base;
            mVideoParam->duration=formatContext->streams[i]->duration;
            mVideoParam->avCodecParameters=formatContext->streams[i]->codecpar;

            int num=formatContext->streams[i]->avg_frame_rate.num;
            int den=formatContext->streams[i]->avg_frame_rate.den;
            if (num>0&&den>0){
                int fps=num/den;
                mVideoParam->defaultDelayTime=  1.0 / fps;
                mVideoParam->fps=fps;
            }
        }else if (formatContext->streams[i]->codecpar->codec_type==AVMEDIA_TYPE_AUDIO) {
            if (mAudioPalyer == nullptr) {
                mAudioPalyer = new AudioPlayer(ffStatus,formatContext->streams[i]->codecpar->sample_rate,
                                               nullptr);
                mAudioPalyer->streamIndex = i;
                mAudioPalyer->avCodecParameters = formatContext->streams[i]->codecpar;

                mAudioPalyer->timeBase = formatContext->streams[i]->time_base;
                mAudioPalyer->duration = formatContext->duration/ AV_TIME_BASE;
                if (audioDuration<=0) {
                    audioDuration = formatContext->duration;
                }
            }
        }
    }

}

void FFSeperator::start() {
    if (ffStatus!= nullptr&&!ffStatus->exit){
        mTheadStart=new std::thread(onStart,this);
    }
}
void FFSeperator::prepare() {
    if (ffStatus!= nullptr&&!ffStatus->exit) {
        mThreadPrepared = new std::thread(onPrepare, this);
    }
}

FFSeperator::~FFSeperator() {
    delete mVideoParam;
    delete ffStatus;
    av_bsf_free(&bsf_ctx);
}








